package cn.merryyou.util.controllerUtil;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.*;

/**
 * @author eiven
 * @date 2018年3月19日 Updates .....
 */
public class JsonbjectParser {

    private static Map<String, Object> simpleTypes = null;

    public JsonbjectParser() {
        if (simpleTypes == null) {
            simpleTypes = new HashMap<String, Object>();
            simpleTypes.put("int", Integer.parseInt("0"));
            simpleTypes.put("float", Float.parseFloat("0.0f"));
            simpleTypes.put("double", Double.parseDouble("0d"));
            simpleTypes.put("long", Long.parseLong("0"));
            simpleTypes.put("boolean", Boolean.parseBoolean("false"));
        }
    }

    /**
     * parse Array
     *
     * @param array
     * @param cls
     * @return
     * @throws Exception
     */
    public <T> List<T> parseList(JSONArray array, Class<T> cls) throws Exception {
        List<T> list = new ArrayList<T>();
        if (array == null) {
            return list;
        }
        int size = array.size();
        if (size > 0) {
            for (int index = 0; index < size; index++) {
                Object obj = array.get(index);
                if (obj instanceof JSONObject) {
                    JSONObject source = array.getJSONObject(index);
                    if (source == null) {
                        if (obj != null) {
                            T object = (T) obj;
                            list.add(object);
                        } else {
                            list.add(null);
                        }
                        // list.add(<T>obj);
                    } else {
                        T object = parseItem(source, cls);
                        list.add(object);
                    }

                } else if (obj instanceof String) {
                    list.add((T) obj);
                } else if (simpleTypes.keySet().contains(obj.getClass())) {
                    try {
                        Object value = null;
                        if ("int".equals(obj.getClass().getSimpleName())) {
                            value = Integer.parseInt(String.valueOf(obj));
                        } else if ("float".equals(obj.getClass().getSimpleName())) {
                            value = Float.parseFloat(String.valueOf(obj));
                        } else if ("double".equals(obj.getClass().getSimpleName())) {
                            value = Double.parseDouble(String.valueOf(obj));
                        } else if ("long".equals(obj.getClass().getSimpleName())) {
                            value = Long.parseLong(String.valueOf(obj));
                        } else if ("boolean".equals(obj.getClass().getSimpleName())) {
                            value = Boolean.parseBoolean(String.valueOf(obj));
                        }
                        list.add((T) value);
                    } catch (Exception e) {
                    }
                }
            }
        }
        return list;
    }

    /**
     * parse Item
     *
     * @param jobject json 对象 代转换的数据
     * @param cls
     * @return
     * @throws Exception
     */
    public <T> T parseItem(JSONObject jobject, Class<T> cls) throws Exception {
        final T object = cls.newInstance();
        if ((object instanceof Map) && jobject != null) {
            ((Map) object).putAll(jobject);
            return object;
        }
        final Set<Field> fields = Reflector.getAllDeclaredFields(cls);
        if (fields != null && fields.size() > 0) {
            for (Field field : fields) {
                final String fieldName = field.getName();
                if ("serialVersionUID".equals(fieldName)) {
                    continue;
                }
                if (Modifier.isFinal(field.getModifiers())) {
                    continue;
                }
                if (Modifier.isStatic(field.getModifiers())) {
                    continue;
                }
                if (Modifier.isAbstract(field.getModifiers())) {
                    continue;
                }
                if (Modifier.isSynchronized(field.getModifiers())) {
                    continue;
                }
                field.setAccessible(true);
                final Class<?> fieldClz = field.getType();
                final String fieldClzName = fieldClz.getName();

                if (fieldClz.isPrimitive()) {
                    if (simpleTypes.keySet().contains(fieldClzName)) {
                        try {
                            Object value = null;
                            if ("int".equals(fieldClzName)) {
                                value = Integer.parseInt(jobject.getString(fieldName));
                            } else if ("float".equals(fieldClzName)) {
                                value = Float.parseFloat(jobject.getString(fieldName));
                            } else if ("double".equals(fieldClzName)) {
                                value = Double.parseDouble(jobject.getString(fieldName));
                            } else if ("long".equals(fieldClzName)) {
                                value = Long.parseLong(jobject.getString(fieldName));
                            } else if ("boolean".equals(fieldClzName)) {
                                value = Boolean.parseBoolean(jobject.getString(fieldName));
                            }
                            field.set(object, value);
                        } catch (Exception e) {
                            field.set(object, simpleTypes.get(fieldClzName));
                        }
                    }
                } else {
                    if (Collection.class.isAssignableFrom(fieldClz)) {
                        ParameterizedType pt = (ParameterizedType) field.getGenericType();
                        Class<?> fieldListClz = (Class<?>) pt.getActualTypeArguments()[0];
                        try {
                            field.set(object, parseList(jobject.getJSONArray(fieldName), fieldListClz));
                        } catch (Exception e) {
                            field.set(object, null);
                        }
                    } else {
                        try {
                            Object value = null;
                            if (fieldClz.isAssignableFrom(String.class)) {
                                value = jobject.get(fieldName);
                            } else if (fieldClz.isAssignableFrom(Integer.class)) {
                                value = Integer.parseInt(jobject.getString(fieldName));
                            } else if (fieldClz.isAssignableFrom(Float.class)) {
                                value = Float.parseFloat(jobject.getString(fieldName));
                            } else if (fieldClz.isAssignableFrom(Double.class)) {
                                value = Double.parseDouble(jobject.getString(fieldName));
                            } else if (fieldClz.isAssignableFrom(Long.class)) {
                                value = Long.parseLong(jobject.getString(fieldName));
                            } else if (fieldClz.isAssignableFrom(Boolean.class)) {
                                value = Boolean.parseBoolean(jobject.getString(fieldName));
                            } else {
                                value = parseItem(jobject.getJSONObject(fieldName), fieldClz);
                            }
                            field.set(object, value);
                        } catch (Exception e) {
                            if (simpleTypes.containsKey(fieldClz.getSimpleName().toLowerCase())) {
                                field.set(object, simpleTypes.get(fieldClz.getSimpleName().toLowerCase()));
                            } else {
                                field.set(object, null);
                            }
                        }

                        //						if(fieldClz.isAssignableFrom(String.class)) {
                        //							try {
                        //								field.set(object, jobject.get(fieldName));
                        //							} catch (Exception e) {
                        //								field.set(object,null);
                        //							}
                        //						} else if(fieldClz.isAssignableFrom(Integer.class)) {
                        //							try {
                        //								field.set(object,  Integer.parseInt(jobject.getString(fieldName)));
                        //							} catch (Exception e) {
                        //								field.set(object,0);
                        //							}
                        //						} else if(fieldClz.isAssignableFrom(Long.class)) {
                        //							try {
                        //								field.set(object,  Long.parseLong(jobject.getString(fieldName)));
                        //							} catch (Exception e) {
                        //								field.set(object,0l);
                        //							}
                        //						} else if(fieldClz.isAssignableFrom(Double.class)) {
                        //							try {
                        //								field.set(object, Double.parseDouble(jobject.getString(fieldName)));
                        //							} catch (Exception e) {
                        //								field.set(object,0d);
                        //							}
                        //						} else if(fieldClz.isAssignableFrom(Float.class)) {
                        //							try {
                        //								field.set(object, Float.parseFloat(jobject.getString(fieldName)));
                        //							} catch (Exception e) {
                        //								field.set(object,0f);
                        //							}
                        //						} else {
                        //							try {
                        //								field.set(object, parseItem(jobject.getJSONObject(fieldName), fieldClz));
                        //							} catch (Exception e) {
                        //								field.set(object,null);
                        //							}
                        //						}
                    }
                }
            }
        }
        return object;
    }
}
